#include "Buffer.h"
#include "Logger.h"

char* Buffer::Begin() {
    return &*buffer_.begin();
}

void Buffer::MakeSpace(size_t len) {
    if (PrependableBytes() + WriteableBytes() >= len + PrependSize) {
        // 可以将readable部分挪腾
        // step1: 将可读区域拷贝到开头并更新可读偏移量
        size_t rsz = ReadableBytes();
        std::copy(Peek(), Peek() + rsz, buffer_.begin() + PrependSize);
        read_index_ = PrependSize;
        // step2: 更新
        write_index_ = read_index_ + rsz;
    } else {
        // 只能扩容了
        buffer_.resize(write_index_ + len);
    }
}

void Buffer::EnSureWriteableBytes(size_t len) {
    if (WriteableBytes() < len) {
        MakeSpace(len);
    }
}

Buffer::Buffer(int initsize) : buffer_(initsize + PrependSize), read_index_(PrependSize), write_index_(PrependSize) {}

size_t Buffer::ReadableBytes() {
    return write_index_ - read_index_;
}
size_t Buffer::WriteableBytes() {
    return buffer_.size() - write_index_;
}
size_t Buffer::PrependableBytes() {
    return read_index_;
}

// 返回缓冲区可读数据起始地址
char* Buffer::Peek() {
    return Begin() + read_index_;
}

// 标记数据已消费
void Buffer::Retrieve(size_t len) {
    if (len < ReadableBytes()) {
        read_index_ += len;
    } else {
        RetrieveAll();
    }
}

void Buffer::RetrieveAll() {
    // 读区为0，相当于重置缓冲区
    read_index_ = PrependSize;
    write_index_ = PrependSize;
}

// 把onMessage函数上报的Buffer数据转成string类型的数据返回
std::string Buffer::RetrieveAsString(size_t len) {
    std::string result(Peek(), len);
    Retrieve(len);
    return result;
}

std::string Buffer::RetrieveAllAsString() {
    return RetrieveAsString(ReadableBytes());
}

// 把[data, data+len]内存上的数据添加到writeable缓冲区当中
void Buffer::Append(const char* data, size_t len) {
    EnSureWriteableBytes(len);
    std::copy(data, data + len, Begin() + write_index_);
    write_index_ += len;
}

// read / write
/**
 * 从fd上读取数据 Poller工作在LT模式
 * Buffer缓冲区是有大小的！ 但是从fd上读取数据的时候 却不知道tcp数据的最终大小
 *
 * 从socket读到缓冲区的方法是使用readv先读至buffer_，
 * Buffer_空间如果不够会读入到栈上65536个字节大小的空间，然后以append的
 * 方式追加入buffer_。既考虑了避免系统调用带来开销，又不影响数据的接收。
 **/

// struct iovec {
//     void* iov_base; /* Starting address */
//     size_t iov_len; /* Size of the memory pointed to by iov_base. */
// };
// UNDERSTAND
int Buffer::ReadFd(int fd) {
    char buf[1024];
    struct iovec iov[2];
    size_t writeable = WriteableBytes();
    iov[0].iov_base = Begin() + write_index_;
    iov[0].iov_len = WriteableBytes();
    iov[1].iov_base = buf;
    iov[1].iov_len = sizeof(buf);
    int iovcnt = writeable >= sizeof(buf) ? 1 : 2;
    ssize_t ret = readv(fd, iov, iovcnt);
    if (ret < 0) {
        // what? error
    } else if (ret <= writeable) {
        write_index_ += ret;
    } else {
        write_index_ = buffer_.size();
        Append(buf, ret - writeable);  // 对buffer_扩容 并将buf存储的另一部分数据追加至buffer_
    }
    return ret;
}

int Buffer::WriteFd(int fd) {
    ssize_t n = write(fd, Peek(), ReadableBytes());
    return n;
}

const char Buffer::CRLF[] = "\r\n";
